#pragma once
#include <iostream>
#include <memory>
#include <jsoncpp/json/json.h>

// #define SelfDefine 1
namespace Protocol
{
    const std::string ProSep = " ";
    const std::string LinkBreakSep = "\n";

    // // "len\nx op y\n"
    // \n 不属于报文的一部分，这是约定
    std::string Encode(const std::string &message) // 编码
    {
        std::string len = std::to_string(message.size());
        std::string package = len + LinkBreakSep + message + LinkBreakSep;
        return package;
    }

    // 无法保证package就是一个独立完整的报文
    // "l
    // "len
    // "len\n
    // "len\nx
    // "len\nx op
    // "len\nx op y
    // "len\nx op y\n"              // 这个就是一个完整的报文
    // "len\nx op y\n""len
    // "len\nx op y\n""len\n
    // "len\nx op
    // "len\nx op y\n""len\nx op y\n"
    // "len\nresult code\n""len\nresult code\n"

    bool Decode(std::string &package, std::string *message) // 解码
    {
        // 先找\n
        auto pos = package.find(LinkBreakSep);
        if (pos == std::string::npos)
            return false;
        std::string lens = package.substr(0, pos);
        int messagelen = std::stoi(lens);
        int total = lens.size() + messagelen + LinkBreakSep.size() * 2;
        if (package.size() < total)
        {
            return false;
        }
        *message = package.substr(pos + LinkBreakSep.size(), messagelen);
        package.erase(0, total);
        return true;
    }

    class Request
    {
    public:
        Request()
        {
        }

        Request(int x, int y, char op)
            : _data_x(x), _data_y(y), _oper(op)
        {
        }

        void INC()
        {
            _data_x++;
            _data_y++;
        }

        void Debug()
        {
            std::cout << "_data_x: " << _data_x << std::endl;
            std::cout << "_data_y: " << _data_x << std::endl;
            std::cout << "_oper: " << _oper << std::endl;
        }

        bool Serializate(std::string *out) // 将结构化字段进行序列化 "x op y"
        {
#ifdef SelfDefine
            *out = std::to_string(_data_x) + ProSep + _oper + ProSep + std::to_string(_data_y);
            return true;
#else
            // 使用Json进行序列化
            Json::Value root;
            root["datax"] = _data_x;
            root["datay"] = _data_y;
            root["oper"] = _oper;
            Json::FastWriter writer;
            *out = writer.write(root);
            return true;
#endif
        }

        bool Deserialize(const std::string &in) // 反序列化
        {
#ifdef SelfDefine
            auto left = in.find(ProSep);
            if (left == std::string::npos)
                return false;
            auto right = in.rfind(ProSep);
            if (right == std::string::npos)
                return false;
            _data_x = std::stoi(in.substr(0, left));
            _data_y = std::stoi(in.substr(right + ProSep.size()));
            std::string opers = in.substr(left + ProSep.size(), right - (left + ProSep.size()));
            if (opers.size() != 1)
                return false;
            _oper = opers[0];
            return true;
#else
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);
            _data_x = root["data_x"].asInt();
            _data_y = root["data_y"].asInt();
            _oper = root["oper"].asInt();
            return res;

#endif
        }

        int GetX()
        {
            return _data_x;
        }

        int GetY()
        {
            return _data_y;
        }

        char GetOper()
        {
            return _oper;
        }

    private:
        // 报文的自描述字段
        // "len\nx op y\n"
        int _data_x;
        int _data_y;
        char _oper;
    };

    class Response
    {
    public:
        Response() {}
        Response(int result, int code) : _result(result), _code(code)
        {
        }

        bool Serializate(std::string *out) // 将结构化字段进行序列化 "_result _code"
        {
#ifdef SelfDefine
            *out = std::to_string(_result) + ProSep + std::to_string(_code);
            return true;
#else
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;
            Json::FastWriter writer;
            *out = writer.write(root);
            return true;

#endif
        }

        bool Deserialize(const std::string &in) // 反序列化
        {
#ifdef SelfDefine
            auto pos = in.find(ProSep);
            if (pos == std::string::npos)
                return false;
            _result = std::stoi(in.substr(0, pos));
            _code = std::stoi(in.substr(pos + ProSep.size()));
            return true;
#else
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);
            _result = root["result"].asInt();
            _code = root["code"].asInt();
            return res;

#endif
        }

        void SetResult(int result)
        {
            _result = result;
        }

        void SetCode(int code)
        {
            _code = code;
        }

        int GetResult()
        {
            return _result;
        }

        int GetCode()
        {
            return _code;
        }

        std::string GetCodeString(int code)
        {
            switch (code)
            {
            case 0:
                return "Success";
            case 1:
                return " DivZeroErr";
            case 2:
                return "ModZeroErr";
            case 3:
                return "UnKnownOper";
            }
            return std::string();
        }

    private:
        // "len\n_result _code\n"
        int _result;
        int _code;
    };

    // 工厂设计模式
    class Factory
    {

    public:
        std::shared_ptr<Request> BuildRequest()
        {
            std::shared_ptr<Request> req = std::make_shared<Request>();
            return req;
        }

        std::shared_ptr<Request> BuildRequest(int x, int y, char op)
        {
            std::shared_ptr<Request> req = std::make_shared<Request>(x, y, op);
            return req;
        }

        std::shared_ptr<Response> BuildResponse()
        {
            std::shared_ptr<Response> res = std::make_shared<Response>();
            return res;
        }

        std::shared_ptr<Response> BuildResponse(int result, int code)
        {
            std::shared_ptr<Response> res = std::make_shared<Response>(result, code);
            return res;
        }
    };
}